﻿namespace Pub.Class
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Threading;

    public class SafeDictionarySlim<K, V> : ISafeDictionary<K, V>, IEnumerable<KeyValuePair<K, V>>, IEnumerable
    {
        private readonly IDictionary<K, V> cache;
        private readonly ReaderWriterLockSlim cacheLock;

        public SafeDictionarySlim()
        {
            this.cache = new Dictionary<K, V>();
            this.cacheLock = new ReaderWriterLockSlim();
        }

        public ISafeDictionary<K, V> Add(K key, V value)
        {
            this.cacheLock.EnterWriteLock();
            try
            {
                this.cache.Add(key, value);
            }
            finally
            {
                this.cacheLock.ExitWriteLock();
            }
            return this;
        }

        public ISafeDictionary<K, V> AddOrUpdate(K key, V value)
        {
            if (!this.ContainsKey(key))
            {
                this.Add(key, value);
            }
            else
            {
                this[key] = value;
            }
            return this;
        }

        public ISafeDictionary<K, V> Clear()
        {
            this.cacheLock.EnterWriteLock();
            try
            {
                this.cache.Clear();
            }
            finally
            {
                this.cacheLock.ExitWriteLock();
            }
            return this;
        }

        public bool ContainsKey(K key)
        {
            bool flag;
            this.cacheLock.EnterReadLock();
            try
            {
                flag = this.cache.ContainsKey(key);
            }
            finally
            {
                this.cacheLock.ExitReadLock();
            }
            return flag;
        }

        public V Get(K key, Func<V> acquire)
        {
            if (this.cache.ContainsKey(key))
            {
                return this.cache[key];
            }
            V local = acquire();
            this.cache[key] = local;
            return local;
        }

        private IEnumerator<KeyValuePair<K, V>> GetEnumeratorImpl()
        {
            IEnumerator<KeyValuePair<K, V>> enumerator;
            this.cacheLock.EnterReadLock();
            try
            {
                enumerator = this.cache.ToList<KeyValuePair<K, V>>().GetEnumerator();
            }
            finally
            {
                this.cacheLock.ExitReadLock();
            }
            return enumerator;
        }

        public bool Remove(K key)
        {
            bool flag;
            this.cacheLock.EnterWriteLock();
            try
            {
                flag = this.cache.Remove(key);
            }
            finally
            {
                this.cacheLock.ExitWriteLock();
            }
            return flag;
        }

        IEnumerator<KeyValuePair<K, V>> IEnumerable<KeyValuePair<K, V>>.GetEnumerator()
        {
            return this.GetEnumeratorImpl();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumeratorImpl();
        }

        public bool TryGetValue(K key, out V value)
        {
            bool flag;
            this.cacheLock.EnterReadLock();
            try
            {
                flag = this.cache.TryGetValue(key, out value);
            }
            finally
            {
                this.cacheLock.ExitReadLock();
            }
            return flag;
        }

        public int Count
        {
            get
            {
                int count;
                this.cacheLock.EnterReadLock();
                try
                {
                    count = this.cache.Count;
                }
                finally
                {
                    this.cacheLock.ExitReadLock();
                }
                return count;
            }
        }

        public V this[K key]
        {
            get
            {
                V local;
                this.cacheLock.EnterReadLock();
                try
                {
                    local = this.cache[key];
                }
                finally
                {
                    this.cacheLock.ExitReadLock();
                }
                return local;
            }
            set
            {
                this.cacheLock.EnterWriteLock();
                try
                {
                    this.cache[key] = value;
                }
                finally
                {
                    this.cacheLock.ExitWriteLock();
                }
            }
        }

        public ICollection<K> Keys
        {
            get
            {
                ICollection<K> keys;
                this.cacheLock.EnterReadLock();
                try
                {
                    keys = this.cache.Keys;
                }
                finally
                {
                    this.cacheLock.ExitReadLock();
                }
                return keys;
            }
        }

        public ICollection<V> Values
        {
            get
            {
                ICollection<V> values;
                this.cacheLock.EnterReadLock();
                try
                {
                    values = this.cache.Values;
                }
                finally
                {
                    this.cacheLock.ExitReadLock();
                }
                return values;
            }
        }
    }
}

